package com.ligoudan.cli;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;

import com.ligoudan.config.ConfigHelper;
import com.ligoudan.converter.Converter;
import com.ligoudan.core.GenContext;
import com.ligoudan.model.GenImageModel;

class DrawImageInfo {
    public BufferedImage imgSource;
    public int width;
    public int height;
    public int offset;
}


public class Command {

    private static BufferedImage loadImage(File location) {
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(location))) {
            return ImageIO.read(in);
        } catch (IOException e) {
            // LOGGER.severe(e.getLocalizedMessage() + ": " + location);
            throw new RuntimeException(e);
        }
    }

    
    private static String decideImageFormat(String outputPath) {
        int idx = outputPath.lastIndexOf(".");
        if (idx == -1) {
            return "png";
        }
        String suffixFileName = outputPath.substring(idx + 1);
        if ("png".equalsIgnoreCase(suffixFileName)) {
            return suffixFileName;
        }
        if ("jpeg".equalsIgnoreCase(suffixFileName) || "jpg".equalsIgnoreCase(suffixFileName)) {
            return "jpeg";
        }
        return "png";
    }

    private static GenContext buildContext() {
        GenContext context = new GenContext();

        ConfigHelper configHelper = new ConfigHelper();
        Properties genConfig = configHelper.loadConfig();
        GenImageModel genModel = Converter.config2Model(genConfig);

        context.setConfigHelper(configHelper);
        context.setGenImageConfig(genConfig);
        context.setGenImageModel(genModel);
        context.setFormComponents(new LinkedList<>());

        configHelper.storageConfig(genModel);
        return context;
    }

    public static void main(String[] args) {
        // System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName());  //获取当前的执行的方法名
        // System.out.println(Thread.currentThread().getStackTrace()[1].getClassName());   //获取当前的类名
        // System.out.println(Thread.currentThread().getStackTrace()[1].getLineNumber());  //获取当前执行的行数
        // System.out.println(Thread.currentThread().getStackTrace()[1].getFileName());    //获取执行文件名
        // // System.out.println(Thread.currentThread().getStackTrace()[2].getClassName());
        // System.out.println(Thread.currentThread().getStackTrace()[2].getMethodName());//获取上次调用者信息

        if (args.length < 2) {
            System.out.println("Usage: " + Thread.currentThread().getStackTrace()[1].getFileName() + " <output> <input> [...]");
            return;
        }

        String output = args[0];
        
        ArrayList<String> inputs = new ArrayList<String>();
        ArrayList<File> inputFiles = new ArrayList<File>();

        for (int i = 1; i < args.length; i++) {
            inputs.add(args[i]);

            File inputFile = new File(args[i]);
            if(inputFile.isFile()) {
                System.out.println("Input file: " + inputFile.getAbsolutePath());
                inputFiles.add(inputFile);
            }
        }
        
        // File[] imageLocations = fc.getSelectedFiles();
        File[] files = new File[inputFiles.size()];
        inputFiles.toArray(files);

        // context.getGenImageModel().setFiles(imageLocations);
        GenContext context = buildContext();        
        context.getGenImageModel().setFiles(files);

        File file = new File(output);

        GenImageModel model = context.getGenImageModel();

        int width = model.getMaxWidth();
        if (width <= 0) {
            // JOptionPane.showMessageDialog(this, "图片宽度必须大于0", "Oops!", JOptionPane.WARNING_MESSAGE);
            return;
        }

        File[] imageLocations = model.getFiles();

        try {
            List<BufferedImage> images = Arrays.stream(imageLocations).parallel().map(Command::loadImage)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            double height = 0;
            for (BufferedImage image : images) {
                height = (double) width / (double) image.getWidth() * (double) image.getHeight() + height;
            }

            double offset = 0;
            List<DrawImageInfo> drawImageInfoList = new ArrayList<>(images.size());
            for (BufferedImage image : images) {
                double h = (double) width / (double) image.getWidth() * (double) image.getHeight();
                DrawImageInfo imageInfo = new DrawImageInfo();
                imageInfo.width = width;
                imageInfo.height = (int) h;
                imageInfo.offset = (int) offset;
                imageInfo.imgSource = image;
                drawImageInfoList.add(imageInfo);
                offset += h;
            }

            BufferedImage card1 = new BufferedImage(width, (int) height, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = card1.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            long start = System.currentTimeMillis();
/*            try {
                for (DrawImageInfo image : drawImageInfoList) {
                    graphics.drawImage(image.imgSource, 0, image.offset, image.width, image.height, this);
                }
            } finally {
                graphics.dispose();
            }*/


            ExecutorService executor = Executors.newFixedThreadPool(Math.min(drawImageInfoList.size(), 100));
            try {
                List<CompletableFuture<Boolean>> futures2 = drawImageInfoList.stream().map(item ->
                        CompletableFuture.supplyAsync(() -> graphics.drawImage(item.imgSource, 0, item.offset, item.width, item.height, null), executor))
                        .collect(Collectors.toList());
                CompletableFuture<Void> allFutures2 = CompletableFuture.allOf(futures2.toArray(new CompletableFuture[0]));
                allFutures2.thenApply(v -> futures2.stream().map(CompletableFuture::join).collect(Collectors.toList())).join();
            } finally {
                graphics.dispose();
                executor.shutdown();
            }

            System.out.println(System.currentTimeMillis() - start);

//            ImageIO.write(card1, decideImageFormat(outputPath), new BufferedOutputStream(new FileOutputStream(file)));
//            ImageIO.write(card1, decideImageFormat(outputPath), new FileOutputStream(file));
            ImageIO.write(card1, decideImageFormat(output), file);
            System.out.println(System.currentTimeMillis() - start);
            // LOGGER.info("Image create successful!, see " + file.getAbsolutePath());

            String[] options = {"打开查看", "关闭"};
            // int i = JOptionPane.showOptionDialog(this, "已保存至" + file.getAbsolutePath(), "成功啦！",
            //         JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
            // if (i == 0) {
            //     Runtime.getRuntime().exec("explorer.exe /select," + outputPath);
            // }
        } catch (Exception e) {
            e.printStackTrace();
            // JOptionPane.showMessageDialog(this, "生成失败, " + e.getLocalizedMessage(), "出错啦！", JOptionPane.ERROR_MESSAGE);
        } finally {
            // 保存上次执行配置
            // context.getConfigHelper().storageConfig(model);
        }

    }
}
